// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <filesystem>

#include "common/io_file.h"
#include "core/file_format/psf.h"

namespace Core::FileSys {
class MntPoints;
}

namespace Libraries::SaveData {

// Used constexpr to easily use as string
namespace SaveParams {
constexpr std::string_view ACCOUNT_ID = "ACCOUNT_ID";
constexpr std::string_view ATTRIBUTE = "ATTRIBUTE";
constexpr std::string_view CATEGORY = "CATEGORY";
constexpr std::string_view DETAIL = "DETAIL";
constexpr std::string_view FORMAT = "FORMAT";
constexpr std::string_view MAINTITLE = "MAINTITLE";
constexpr std::string_view PARAMS = "PARAMS";
constexpr std::string_view SAVEDATA_BLOCKS = "SAVEDATA_BLOCKS";
constexpr std::string_view SAVEDATA_DIRECTORY = "SAVEDATA_DIRECTORY";
constexpr std::string_view SAVEDATA_LIST_PARAM = "SAVEDATA_LIST_PARAM";
constexpr std::string_view SUBTITLE = "SUBTITLE";
constexpr std::string_view TITLE_ID = "TITLE_ID";
} // namespace SaveParams

using OrbisUserServiceUserId = s32;

class SaveInstance {
    int slot_num{};
    int user_id{};
    std::string game_serial;
    std::string dir_name;

    std::filesystem::path save_path;
    std::filesystem::path param_sfo_path;
    std::filesystem::path corrupt_file_path;

    Common::FS::IOFile corrupt_file;

    PSF param_sfo;
    std::string mount_point;

    int max_blocks{};
    bool exists{};
    bool mounted{};
    bool read_only{};

public:
    // Location of all save data for a title
    static std::filesystem::path MakeTitleSavePath(OrbisUserServiceUserId user_id,
                                                   std::string_view game_serial);

    // Location of a specific save data directory
    static std::filesystem::path MakeDirSavePath(OrbisUserServiceUserId user_id,
                                                 std::string_view game_serial,
                                                 std::string_view dir_name);

    static uint64_t GetMaxBlockFromSFO(const PSF& psf);

    // Get param.sfo path from a dir_path generated by MakeDirSavePath
    static std::filesystem::path GetParamSFOPath(const std::filesystem::path& dir_path);

    static void SetupDefaultParamSFO(PSF& param_sfo, std::string dir_name, std::string game_serial);

    explicit SaveInstance(int slot_num, OrbisUserServiceUserId user_id, std::string game_serial,
                          std::string_view dir_name, int max_blocks = 0);

    ~SaveInstance();

    SaveInstance(const SaveInstance& other) = delete;
    SaveInstance(SaveInstance&& other) noexcept;

    SaveInstance& operator=(const SaveInstance& other) = delete;
    SaveInstance& operator=(SaveInstance&& other) noexcept;

    void SetupAndMount(bool read_only = false, bool copy_icon = false, bool ignore_corrupt = false);

    void Umount();

    [[nodiscard]] std::filesystem::path GetIconPath() const noexcept {
        return save_path / "sce_sys" / "icon0.png";
    }

    [[nodiscard]] bool Exists() const noexcept {
        return exists;
    }

    [[nodiscard]] OrbisUserServiceUserId GetUserId() const noexcept {
        return user_id;
    }

    [[nodiscard]] std::string_view GetTitleId() const noexcept {
        return game_serial;
    }

    [[nodiscard]] const std::string& GetDirName() const noexcept {
        return dir_name;
    }

    [[nodiscard]] const std::filesystem::path& GetSavePath() const noexcept {
        return save_path;
    }

    [[nodiscard]] const PSF& GetParamSFO() const noexcept {
        return param_sfo;
    }

    [[nodiscard]] PSF& GetParamSFO() noexcept {
        return param_sfo;
    }

    [[nodiscard]] const std::string& GetMountPoint() const noexcept {
        return mount_point;
    }

    [[nodiscard]] int GetMaxBlocks() const noexcept {
        return max_blocks;
    }

    [[nodiscard]] bool Mounted() const noexcept {
        return mounted;
    }

    [[nodiscard]] bool IsReadOnly() const noexcept {
        return read_only;
    }

    void CreateFiles();
};

} // namespace Libraries::SaveData
